package com.glasgowcompsoc.musicplayer.ui;

import java.io.IOException;
import com.glasgowcompsoc.musicplayer.R;
import com.glasgowcompsoc.musicplayer.player.PlaylistManager;
import com.glasgowcompsoc.musicplayer.player.Song;

import android.app.Activity;
import android.content.res.AssetManager;
import android.graphics.PixelFormat;
import android.graphics.Typeface;
import android.graphics.drawable.GradientDrawable;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Gallery;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class Player extends Activity {
	/* Update interval for progress bar, in ms. */
	private static final int PROGRESS_BAR_UPDATE_INTERVAL = 1000;

	private PlaylistManager playlistManager;
	private MediaPlayer mediaPlayer;
	private Gallery albumArtGallery;
	private ProgressBar progressBar;
	private TextView timePlayed;
	private TextView timeRemaining;

	private static final Handler handlerTimer = new Handler();

	/* Called once - when the Activity is created. Prepare
	 * the UI and set up any objects this activity may need.
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		/* Set layout for this activity */
		setContentView(R.layout.player);

		/* Set the window to use 8 bit per channel. Gingerbread uses this by default, all version below use less */
		getWindow().setFormat(PixelFormat.RGBA_8888);

		/* Make the background gradient appear slightly better */
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_DITHER);
		((GradientDrawable) findViewById(R.id.player_main_layout).getBackground()).setDither(true);

		/* Load in custom fonts; make it look better! */
		Typeface lightTypeface = Typeface.createFromAsset(getAssets(), "fonts/OpenSans-Light.ttf");
		Typeface boldTypeface = Typeface.createFromAsset(getAssets(), "fonts/OpenSans-ExtraBold.ttf");

		/* Set the TextViews to use the fonts we loaded above */
		TextView artist = (TextView) findViewById(R.id.artist);
		artist.setTypeface(lightTypeface);

		timePlayed = (TextView) findViewById(R.id.time_played);
		timePlayed.setTypeface(lightTypeface);
		timeRemaining = (TextView) findViewById(R.id.time_remaining);
		timeRemaining.setTypeface(lightTypeface);

		TextView title = (TextView) findViewById(R.id.title);
		title.setTypeface(boldTypeface);

		/* Initialise playlist */
		playlistManager = PlaylistManager.getPlaylistManager();
		createPlaylistFromAssets();

		/* Set up the Gallery widget. This is used to display the cover-art for each song. */
		albumArtGallery = (Gallery) findViewById(R.id.playlist_gallery);
		albumArtGallery.setAdapter(new AlbumArtAdapter(this, playlistManager.getCurrentPlaylist()));
		
		/* Register an item selected listener for the cover-art gallery.
		 * When the user selects a "song", start playing it.
		 */
		albumArtGallery.setOnItemSelectedListener(new OnItemSelectedListener() {
			@Override
			public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
				if (mediaPlayer != null) {
					playSong(playlistManager.getSongAt(position));
				}
			}

			@Override
			public void onNothingSelected(AdapterView<?> arg0) {
			}
		});

		/* Fetch progress bar; we'll update the progress value to show how far
		 * into the playing song we are.
		 */
		progressBar = (ProgressBar) findViewById(R.id.progress_bar);
	}

	/* When the activity is paused, pause the song. Normally you would want to 
	 * keep it playing (e.g. so they can listen to music while reading Reddit),
	 * but this player only plays Nyan Cat. And Nyan Cat gets annoying... :)
	 */
	@Override
	public void onPause() {
		super.onPause();

		if (mediaPlayer != null && mediaPlayer.isPlaying()) {
			mediaPlayer.pause();
		}
	}

	/*
	 * Check in the assets directory of the application for mp3 files to load. In a "real" application, we'd check the
	 * Music directory on the SD card and let the user choose music from there.
	 */
	private void createPlaylistFromAssets() {
		AssetManager am = getAssets();

		/* Get a list of files in the assets directory. */
		String[] assetFiles;

		try {
			assetFiles = am.list("");
		} catch (IOException e1) {
			e1.printStackTrace();

			return;
		}

		/* Check if file is an MP3, and add to playlist. */
		for (String file : assetFiles) {
			if (file.toLowerCase().endsWith(".mp3")) {
				Song song;

				try {
					song = new Song(am.openFd(file));
				} catch (IOException e) {
					/* Can't open song; skip to next file. */
					continue;
				}

				playlistManager.addSong(song);
			}
		}
	}

	/* Callback method for the play/pause button when no track is currently playing.
	 * Starts playing a track then sets the button up to pause playback.
	 */
	public void playClick(View v) {
		if (mediaPlayer == null) {
			Song nowPlaying = playSong(playlistManager.currentSong());

			if (nowPlaying == null) {
				// Something went wrong: handle properly
				return;
			}
		} else {
			/* Resume playback */
			mediaPlayer.start();
			
			/* Restart the progress bar updates */
			handlerTimer.postDelayed(r, 0);
			
			createPauseButton();
		}
	}

	/* Callback method for clicks on the play/pause button when a song is playing.
	 * Pauses the current song and sets the button to resume playback.
	 */
	public void pauseClick(View v) {
		if (mediaPlayer.isPlaying())
			mediaPlayer.pause();
		/* Change the "Pause" button to a "Play" button. */
		createPlayButton();
	}

	public void nextClick(View v) {
		nextSong();
	}

	public void previousClick(View v) {
		previousSong();
	}

	private void nextSong() {
		int i = playlistManager.nextSongIndex();
		albumArtGallery.setSelection(i, true);
	}

	private void previousSong() {
		int i = playlistManager.nextSongIndex();
		albumArtGallery.setSelection(i, true);
	}

	/* Plays a song. Returns the song which starts playing, or null if an error occurred. */
	private Song playSong(Song song) {
		if (song == null) {
			/* Toast notifications pop up on the screen for a short time.
			 * One alternative to alert dialogs.
			 */
			Toast.makeText(this, "Cannot play song. Nyan cat is dead.", Toast.LENGTH_SHORT).show();
			return null;
		}

		if (mediaPlayer != null && (mediaPlayer.isPlaying() || mediaPlayer.isLooping())) {
			mediaPlayer.pause();
		}

		Song nowPlaying = song;

		/* Get a MediaPlayer instance for the current song */
		try {
			mediaPlayer = nowPlaying.getMediaPlayer();
		} catch (IOException e) {
			e.printStackTrace();

			/* If an error occurs, just remove from playlist. */
			playlistManager.removeSong(song);

			nextSong();

			return null;
		}

		/* Update the now playing information. */
		TextView artistTextView = (TextView) findViewById(R.id.artist);
		artistTextView.setText(nowPlaying.getArtist());

		TextView titleTextView = (TextView) findViewById(R.id.title);
		titleTextView.setText(nowPlaying.getTitle());

		/* Prepare progress bar to show song progress */
		progressBar.setProgress(0);
		progressBar.setMax(mediaPlayer.getDuration());

		/* Start the handler to update the progress bar */
		handlerTimer.postDelayed(r, 0);

		/* Start playback. */
		mediaPlayer.start();

		/* Listen for playback completed event, then start next song. */
		mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
			@Override
			public void onCompletion(MediaPlayer mediaPlayer) {
				nextSong();
			}
		});

		/* Change the "Play" button to a "Pause" button. */
		createPauseButton();

		return nowPlaying;
	}

	/* This Runnable gets posted to a Handler, which executes the run
	 * method and then posts itself after a certain delay. This is one
	 * way to safely update timers or dynamic interface widgets, without
	 * running everything on the UI thread.
	 */
	public Runnable r = new Runnable() {
		@Override
		public void run() {
			MediaPlayer activeMP = mediaPlayer;
			int progress = activeMP.getCurrentPosition();
			progressBar.setProgress(progress);
			progress = progress / 1000;
			int duration = mediaPlayer.getDuration() / 1000;
			int remaining = duration - progress;

			timePlayed.setText(String.format("%d:%02d", progress / 60, progress % 60));
			timeRemaining.setText(String.format("%d:%02d", remaining / 60, remaining % 60));

			if (mediaPlayer.isPlaying())
				handlerTimer.postDelayed(this, PROGRESS_BAR_UPDATE_INTERVAL);
		}
	};

	/* Change the Play / Resume button into a Pause button. */
	private void createPauseButton() {
		ImageButton playPauseButton = (ImageButton) findViewById(R.id.button_playPause);
		playPauseButton.setImageDrawable(getResources().getDrawable(android.R.drawable.ic_media_pause));

		playPauseButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				pauseClick(v);
			}
		});
	}

	/* Change the Pause button into a Play / Resume button. */
	private void createPlayButton() {
		ImageButton playPauseButton = (ImageButton) findViewById(R.id.button_playPause);
		playPauseButton.setImageDrawable(getResources().getDrawable(android.R.drawable.ic_media_play));

		playPauseButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				playClick(v);
			}
		});
	}
}
